// Copyright (c) 2010 Thomas Stuefe
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#pragma once

using namespace System;

#include "DataType.h"

namespace zencat {
namespace sqlite {


	interface class IDatabase;

	/// <summary>
    /// A prepared statement.
    /// </summary>
	public interface class IStatement {

		/// <summary>
		/// Gets the associated datbase
        /// </summary>
		property IDatabase^ Database {
			IDatabase^ get();
		}

		/// <summary>
		/// Gets the statement sql text
        /// </summary>
		property String^ Sql {
			String^ get();
		}
		
		/// <summary>
		/// Gets the number of parameters on the statement
        /// </summary>
		property int ParameterCount {
			int get();
		}

		/// <summary>
		/// Gets the number of columns on the statement
        /// </summary>
		property int ColumnCount {
			int get();
		}

		/// <summary>
		/// Retrieve the name of a single result column.
		/// <seealso cref="ColumnNames"/>
        /// </summary>
		/// <param name="columnNumber">Column number (zero-based)</param>
		/// <returns>The name of the column of the current result row</returns>
		String^ GetColumnName(int columnNumber);

		/// <summary>
		/// Gets the names of all result columns; an empty array if statement has 
		/// no result columns (insert or update).
		/// <seealso cref="GetColumnName"/>
        /// </summary>
		property array<String^>^ ColumnNames {
			array<String^>^ get();
		}

		/// <summary>
		/// Retrieve the type of a single column or the current result row.
		/// (Note: the result type can vary from Row to Row, as sqlite does not have rigid typing; 
		/// see http://www.sqlite.org/datatype3.html)
		/// <seealso cref="ColumnTypes"/>
        /// </summary>
		/// <param name="columnNumber">Column number (zero-based)</param>
		/// <returns>The type of the column of the current result row</returns>
		DataType GetColumnType(int columnNumber);

		/// <summary>
		/// Gets the types of all columns or the current result row; an empty array if statement has 
		/// no result columns (insert or update).
		/// (Note: the result type can vary from Row to Row, as sqlite does not have rigid typing; 
		/// see http://www.sqlite.org/datatype3.html)
		/// <seealso cref="GetColumnType"/>
        /// </summary>
		property array<DataType>^ ColumnTypes {
			array<DataType>^ get();
		}

		/// <summary>
		/// finalizes and closes the statement.
        /// </summary>
		void Close();

		/// <summary>
		/// Gets a value indicating whether the statement is still open.
        /// </summary>
		property bool IsOpen {
			bool get();
		}

		/// <summary>
		/// Gets a value indicating whether the statement was executed (<see cref="Step"/>) and 
		/// returned data.
        /// </summary>
		property bool HasData {
			bool get();
		}

		/// <summary>
		/// reset the statement. This will reset the values of all bound parameters.
		/// It also will reset the internal parameter counter, allowing you to use the bind...ToNextParameter 
		/// methods again.
		/// See also: http://www.sqlite.org/c3ref/reset.html
		/// </summary>
		void Reset();

		/// <summary>
		/// execute the statement one step further (see http://www.sqlite.org/c3ref/step.html)
		/// </summary>
		/// <returns>true if there are data data to be retrieved, false if not</returns>
		bool Step();



		// setting parameters:

		/// <summary>
		/// Binds a string value to a specific parameter.
        /// </summary>
		/// <param name="value">value to bind. null is allowed and sets the parameter to SQL NULL.</param>
		/// <param name="index">parameter number, starting at 1.</param>
		void BindStringToParameter(String^ value, int index);

		/// <summary>
		/// Binds an 64 bit integer value to a specific parameter.
        /// </summary>
		/// <param name="value">value to bind.</param>
		/// <param name="index">parameter number, starting at 1.</param>
		void BindInt64ToParameter(Int64 value, int index);

		/// <summary>
		/// Binds an 64bit IEEE float value to a specific parameter.
        /// </summary>
		/// <param name="index">parameter number, starting at 1.</param>
		/// <param name="value">value to bind.</param>
		void BindDoubleToParameter(Double value, int index);

		/// <summary>
		/// sets a parameter to SQL NULL
        /// </summary>
		/// <param name="index">parameter number, starting at 1.</param>
		void BindNullToParameter(int index);

		/// <summary>
		/// Convenience function, binds all parameters in one go. 
		/// Note: Might not work if the SQL contains parameters with directly given numbers 
		///  (?NNN) and there are gaps in the numbering.
		/// </summary>
		/// <param name="values">parameter values. There must be exactly as many parameter 
		///   values as there are parameters in the statement. 
		///   null values are allowed and set the corresponding parameter to NULL.
		/// </param>
		void BindParameters(array<String^>^ values);


		// Result set interface:

		/// <summary>
		/// retrieves a String result value (see sqlite3_column_text16()).
		/// </summary>
		/// <param name="column">column number, starting at 0.</param>
		/// <returns>value in this column, null for SQL NULL</returns>
		String^ ColumnValueString(int column);

		/// <summary>
		/// retrieves a 64bit integer result value (see sqlite3_column_int64()).
		/// </summary>
		/// <param name="column">column number, starting at 0.</param>
		/// <returns>The result in this column, 0 for SQL NULL </returns>
		Int64 ColumnValueInt64(int column);

		/// <summary>
		/// retrieves a 64bit IEEE float result value (see sqlite3_column_double()).
		/// See also: http://www.sqlite.org/c3ref/result_blob.html
		/// </summary>
		/// <param name="column">column number, starting at 0.</param>
		/// <returns>The result in this column, 0.0 for SQL NULL</returns>
		Double ColumnValueDouble(int column);

		/// <summary>
		/// checks whether value in the column is SQL NULL.
		/// </summary>
		/// <param name="column">column number, starting at 0.</param>
		/// <returns>true if value is NULL, false if not.</returns>
		bool ColumnValueIsNULL(int column);

		/// <summary>
		/// Convenience function, returns all values in all columns in one go.
		/// </summary>
		/// <returns> Array of strings for all values; null for SQL NULL. </returns>
	    array<String^>^ ColumnValues();

		///////////

	}; // end IStatement


} // end namespace sqlite

} // end namespace zencat
